home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / fsort.com / FSORT.C next >
Encoding:
C/C++ Source or Header  |  1990-02-01  |  7.3 KB  |  239 lines

  1. /* FSORT.C - sort a flat file using an array of indices to the strings. */
  2. extern unsigned int _stklen=15000;
  3. #define MAXITEMS  12
  4. #define BUFSIZE    1000
  5. #define MESSAGE    5
  6. #define READING "READING"
  7. #define WRITING "WRITING"
  8. #define SORTING "SORTING"
  9. #define NOTFLAT "\r\nRecords are not of identical length - exiting"
  10. #include <stdio.h>
  11. #include <conio.h>
  12. #include <alloc.h>
  13. #include <ctype.h>
  14. #include <dos.h>
  15. #include <stat.h>
  16. #include <io.h>
  17. #include <fcntl.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. typedef unsigned int SORTINFO;/* Hold line's array index only. */
  21. SORTINFO *position;/* Holds indices to file. */
  22. char *str1, *str2, *base;  /* Pointer to base of array to be sorted. */
  23. long lbase, memleft=65000L;
  24.  
  25. int clrline(int line);
  26. int compare(SORTINFO *s1, SORTINFO *s2);
  27. int copydata(char *buffer, int nitems, int lindex);
  28. int countconsec(int jj, int ii);
  29. int fileinfo(char *inname);
  30. void *getmem(void *ptr, long nbytes);
  31. int givecount(unsigned int count);
  32. int rcenter(char *str, int line);
  33.  
  34. char *readbuf, *pbuf, *ptr, temp[BUFSIZE];
  35. int off[MAXITEMS], l[MAXITEMS];
  36. int order=1, nitems;
  37. unsigned long filesize, nrecs, elsize, pos;
  38. unsigned int recsize, nread, readsize, left;
  39. char line[300];
  40. char explain[]="\r\nUsage:  FSORT <infile> <outfile> <order> <col1>...<coln>\r\n\n"
  41.     "   <infile> - file to sort (must be flat file)\r\n"
  42.     "  <outfile> - file to make\r\n"
  43.     "    <order> - A for Ascending, D for Descending\r\n"
  44.     " <col1>...<coln> - column pairs to use\r\n\n"
  45.     " For example: FSORT  MYDATA.DTA  MYSDATA.DTA  A  1 5  25 30  22 26\r\n";
  46.  
  47. /****************************/
  48. /* Clear the line selected. */
  49. /****************************/
  50. int clrline(int line)
  51. {
  52.     gotoxy(1, line);
  53.     clreol();
  54.     return(0);
  55. }
  56. /**********************************/
  57. /* This compares the two strings. */
  58. /**********************************/
  59. int compare(SORTINFO *s1, SORTINFO *s2)
  60. {
  61.     pos = lbase + (*s1)*elsize;
  62.     str1 = (char *) (((pos/16)<<16) | pos%16);
  63.     pos = lbase + (*s2)*elsize;
  64.     str2 = (char *) (((pos/16)<<16) | pos%16);
  65.     return (order*strncmp(str1, str2, elsize));
  66. }
  67. /***********************************************/
  68. /* This copies the data to the buffer to sort. */
  69. /***********************************************/
  70. int copydata(char *buffer, int nitems, int lindex)
  71. {
  72.     register int i, j;
  73.     if (buffer[recsize-1]!='\n'){
  74.         clrscr();
  75.         cprintf(NOTFLAT);
  76.         exit(16);
  77.     }
  78.     pos = lbase + lindex*elsize;
  79.     ptr = (char *) (((pos/16)<<16) | pos%16);
  80.     for (j=i=0; i<nitems; j+=l[i], i++)
  81.         strncpy(&ptr[j], &buffer[off[i]], l[i]);
  82.     return 0;
  83. }
  84. /**************************************************************/
  85. /* This counts how many cosecutive records there are to read. */
  86. /**************************************************************/
  87. int countconsec(int jj, int ii)
  88. {
  89.     register int i, j;
  90.     int count;
  91.     for (i=ii,j=jj,count=1; i<nrecs-1 && j<nread-1; i++, j++, count++)
  92.         if (position[i+1] != position[i]+1) break;
  93.     return (count);
  94. }
  95. /*********************************************************************/
  96. /* This determines the number of bytes per record of a fixed-record- */
  97. /* length file.                                                                        */
  98. /*********************************************************************/
  99. int fileinfo(char *inname)
  100. {
  101.     FILE *infile;
  102.     char buffer[BUFSIZE];
  103.     infile = fopen(inname, "rb");
  104.     if (infile==NULL){
  105.         cprintf("File %s not found\n", inname);
  106.         exit(0);
  107.     }
  108.     fgets(buffer, BUFSIZE, infile);
  109.     fclose(infile);
  110.     return(strlen(buffer));
  111. }
  112. /**************************************************/
  113. /* Gets a chunk of memory to use for the sort.     */
  114. /**************************************************/
  115. void *getmem(void *ptr, long nbytes)
  116. {
  117.     ptr = farmalloc(nbytes);
  118.     if (ptr == NULL) {
  119.         clrline(MESSAGE);
  120.         rcenter(" Out of memory", MESSAGE);
  121.         exit(99);
  122.     }
  123.     return (ptr);
  124. }
  125. /*****************************************/
  126. /* This updates the count on the screen. */
  127. /*****************************************/
  128. int givecount(unsigned int count)
  129. {
  130.     gotoxy(38, 12);
  131.     cprintf("%d", count+1);
  132.     return 0;
  133. }
  134. /********************************************************/
  135. /* Centers a string on the screen on the line selected. */ 
  136. /********************************************************/
  137. int rcenter(char *str, int line)
  138. {
  139.     clrline(line);
  140.     gotoxy(41-strlen(str)/2, line);
  141.     return(cputs(str));
  142. }
  143. int main(int argc, char *argv[])
  144. {
  145.     register unsigned int i, j;
  146.     int inf, outf, count;
  147.     if (argc<4) {
  148.         cprintf(explain);
  149.         exit(16);
  150.     }
  151.     recsize = fileinfo(argv[1]);  /* Get record size. */
  152.     outf = open(argv[2], O_CREAT|O_TRUNC|O_BINARY, S_IWRITE);
  153.     inf = _open(argv[1], O_RDONLY|O_BINARY); /* Get size of file to sort. */
  154.     filesize = filelength(inf);
  155.     nrecs = filesize/recsize;
  156.  
  157.     if (toupper(argv[3][0])=='D') order = -1; /* Get sort order. */
  158.     else if (toupper(argv[3][0])!='A') { /* Not legal - give message. */
  159.         cprintf("\r\nUnknown sort order specified- not A or D\r\n");
  160.         exit(99);
  161.     }
  162.     /* If no offset is specified, assume we use column 1. */
  163.     nitems = argc - 4;        /* Count number of items to pair. */
  164.     nitems = nitems/2 + 1;  /* Count number of pairs. */
  165.  
  166.     for (elsize=j=0, i=4; i<argc && i<nitems*2+4; i+=2, j++){
  167.         off[j] = atoi(argv[i])-1;
  168.         if (off[j] < 0){
  169.             cprintf("\r\nColumn %s not valid\r\n", argv[i]);
  170.             exit(99);
  171.         }
  172.         l[j] = (off[j+1] = atoi(argv[i+1])-1) - off[j] +1;
  173.         if (l[j] < 0){
  174.             cprintf("\r\nColumn %s cannot be smaller than the preceding column (%s).\r\n", argv[i+1], argv[i]);
  175.             exit(99);
  176.         }
  177.         elsize += l[j];
  178.     }
  179.     if (!elsize || argc==4) { /* Assume sort on first 20 columns. */
  180.         off[0] = nitems = 1;
  181.         l[0] = elsize = 20;
  182.     }
  183.  
  184.     /* Build table used to hold the string indexes. */
  185.     position = (SORTINFO *) getmem((SORTINFO *) position, nrecs * sizeof(SORTINFO));
  186.  
  187.     /* Get memory for table to use for sorting. */
  188.     base = getmem(base, nrecs * elsize);
  189.     lbase = (unsigned long) FP_SEG(base);/* Convert pointer to a long. */
  190.     lbase *= 16;
  191.     lbase += FP_OFF(base);
  192.     for (i=0; i<nrecs; i++) position[i] = i;
  193.  
  194.     memleft = min(65000L, farcoreleft());
  195.     nread = (unsigned int) min(nrecs, memleft/ recsize);
  196.     readsize = (unsigned) nread*recsize;
  197.     pbuf = getmem(pbuf, readsize);/* Get temporary buffer for reading. */
  198.  
  199.     /* Read file in and build table of sortable data. */
  200.     rcenter(READING, MESSAGE);
  201.     for (i=0; i<nrecs; ){
  202.         left = (unsigned) _read(inf, pbuf, readsize);
  203.         for (j=0; j<left/recsize && i<nrecs; j++, i++){
  204.             copydata(&pbuf[j*recsize], nitems, i);
  205.             if (i%25 == 24) givecount(i);
  206.         }
  207.     }
  208.     givecount(i);
  209.    farfree(pbuf);
  210.  
  211.     /* Sort file, using qsort. */
  212.     rcenter(SORTING, MESSAGE);
  213.     qsort(&position[0], nrecs, sizeof(SORTINFO), compare);
  214.  
  215.     /* Write file back out. */
  216.    clrline(12);
  217.     pbuf = (char *) getmem((char *) pbuf, readsize);
  218.     for (i=0; i<nrecs; ) {
  219.         rcenter(WRITING, MESSAGE);
  220.             /* Fill up buffer with records to write. */
  221.         for (j=0; j<nread && i<nrecs; i+=count, j+=count){
  222.             /* See if there are any consecutive records to read. */
  223.             count = countconsec(i, j);
  224.             lseek(inf, ((long) position[i]) * recsize, SEEK_SET);
  225.             _read(inf, &pbuf[j*recsize], count*recsize);
  226.             givecount(i+count);
  227.         }
  228.         givecount(i);
  229.         write(outf, pbuf, j*recsize); /* Write out this piece. */
  230.     }
  231.     givecount(i);
  232.     farfree(pbuf);
  233.    farfree(base);
  234.    farfree(position);
  235.     close(outf);
  236.     close(inf);
  237.     exit(0);
  238. }
  239.